package com.longkey.workflow.client.canvas
{
	import com.longkey.workflow.client.constants.AnchorType;
	import com.longkey.workflow.client.constants.ElementType;
	import com.longkey.workflow.client.constants.StatusType;
	import com.longkey.workflow.client.control.Context;
	import com.longkey.workflow.client.event.PropertyEvent;
	import com.longkey.workflow.client.util.MathUtil;
	
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	public class FlowLink extends BaseElement
	{
		private var _startNode:WorkNode = null;
		private var _endNode:WorkNode = null;
		private var _mousePoint:Point = new Point();
		
		private var _xFrom:Number = 0;
		private var _yFrom:Number = 10;
		private var _xTo:Number = 10;
		private var _yTo:Number = 0;
//		private var _fromPoint:Point = new Point();
//		private var _toPoint:Point = new Point();
		private var _bidirection:Boolean = false;
		
		public var isTemp:Boolean = false;
		
		public function FlowLink(){
			super(ElementType.LINK);
//			this._fromPoint.x = 0;
//			this._fromPoint.y = 10;
//			this._toPoint.x = 10;
//			this._toPoint.y = 0;
		}
		
		override protected function init():void
		{
			// TODO Auto Generated method stub
			super.init();
			this.status = StatusType.LINE_NORMAL;
			this.addEventListener(MouseEvent.CLICK, mouseClickHandler);
			this.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
			this.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
			this.addEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler);
			this.addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
			this.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
			
		}
		
		public function changeStatus(p:Point):void{
			this.anchor = this.getAnchorTypeByPoint(p);
			switch(this.status){
				case StatusType.LINE_NORMAL:
					switch(this.anchor){
						case AnchorType.LINEEND:
						case AnchorType.LINEMIDDLE:
						case AnchorType.LINESTART:
						case AnchorType.OTHER:
							this.status = StatusType.LINE_SELECT;
							break;
						default:
							break;
					}
					break;
				case StatusType.LINE_HOVER:
					switch(this.anchor){
						case AnchorType.LINEEND:
						case AnchorType.LINEMIDDLE:
						case AnchorType.LINESTART:
						case AnchorType.OTHER:
							this.status = StatusType.LINE_SELECT;
							break;
						default:
							this.status = StatusType.LINE_NORMAL;
							break;
					}
					break;
				case StatusType.LINE_SELECT:					
					switch(this.anchor){
						case AnchorType.LINEEND:
						case AnchorType.LINEMIDDLE:
						case AnchorType.LINESTART:
						case AnchorType.OTHER:
							break;
						default:
							this.status = StatusType.LINE_NORMAL;
							break;
					}
					break;
				case StatusType.LINE_SAMPLE:
					var ele:BaseElement = canvas.getPointElement(p, this.id);
					if(ele is WorkNode){
						this.startNode = WorkNode(ele);
						this.status = StatusType.LINE_DRAW;
					}
					break;
				case StatusType.LINE_DRAW:
					ele = canvas.getPointElement(p, this.id);
					if(ele is WorkNode){
						if(this.startNode == null){
							this.startNode = WorkNode(ele);
						}
						else if(this.endNode == null){
							this.endNode = WorkNode(ele);
						}
						this.status = StatusType.LINE_NORMAL;
						if(this.isTemp){
							canvas.createLinkByTemp();
						}
					}
					break;
				default:
					this.status = StatusType.LINE_NORMAL;
					break;
			}
		}
		
		private function mouseClickHandler(event:MouseEvent):void{
			var p:Point = canvas.getDiagramPoint(event);
			this.changeStatus(p);
			if(this.status == StatusType.LINE_SELECT){
				var e:PropertyEvent = new PropertyEvent("openPropEditor");
				e.elementId = this.id;
				e.elementType = this.type;
				e.owner = this;
				Context.propView.dispatchEvent(e);
			}
		}
		
		private function mouseDownHandler(event:MouseEvent):void{
			
		}
		
		private function mouseUpHandler(event:MouseEvent):void{
			
		}
		
		private function mouseOverHandler(event:MouseEvent):void{
			
		}
		
		private function mouseOutHandler(event:MouseEvent):void{
			
		}
		
		private function mouseMoveHandler(event:MouseEvent):void{
			this.anchor = this.getAnchorType(event);
			var p:Point = canvas.getDiagramPoint(event);
			switch(this.status){
				case StatusType.LINE_DRAW:
					this.mousePoint = p;
					break;
				default:
					break;
			}			
		}
		
		private function getAnchorTypeByPoint(p:Point):int{
			var anchorType:int = AnchorType.NOP;
			var dis:Number = MathUtil.calcDistanceToLine(this.fromPoint, this.toPoint, p);
			if(dis <= 5){
				anchorType = AnchorType.OTHER;
				if(dis <= 3){
					var len:Number = MathUtil.calcDistance(this.fromPoint, this.toPoint);
					var anchorlen:Number = Math.min(15, len/3);
					dis = MathUtil.calcDistance(this.fromPoint, p);
					if(dis <= anchorlen){
						anchorType = AnchorType.LINESTART;
					}
					else{
						dis = MathUtil.calcDistance(this.toPoint, p);
						if(dis <= anchorlen){
							anchorType = AnchorType.LINEEND;
						}
						else{
							anchorType = AnchorType.LINEMIDDLE;
						}
					}
				}
			}
			return anchorType;
		}
		
		protected function getAnchorType(event:MouseEvent):int{
			return this.getAnchorTypeByPoint(canvas.getDiagramPoint(event));
		}
		
		private function resize():void{
			var x1:Number = 0;
			var y1:Number = 0;
			var x2:Number = 0;
			var y2:Number = 0;
			if(_startNode == null){
				if(_endNode == null){
					x1 = _mousePoint.x - 10;
					y1 = _mousePoint.y + 10;
					x2 = _mousePoint.x + 10;
					y2 = _mousePoint.y - 10;
				}
				else{
					x1 = _mousePoint.x;
					y1 = _mousePoint.y;
//					var p:Point = _endNode.getLinkPoint(_mousePoint);
					var p:Point = _endNode.getCenterPoint();
					x2 = p.x;
					y2 = p.y;
				}
			}
			else{
				if(_endNode == null){
//					p = _startNode.getLinkPoint(_mousePoint);
					p = _startNode.getCenterPoint();
					x1 = p.x;
					y1 = p.y;
					x2 = _mousePoint.x;
					y2 = _mousePoint.y;
				}
				else{
					var p1:Point = _startNode.getCenterPoint();
					var p2:Point = _endNode.getCenterPoint();
					p = _startNode.getLinkPoint(p2);
					x1 = p.x;
					y1 = p.y;
					p = _endNode.getLinkPoint(p1);
					x2 = p.x;
					y2 = p.y;
//					x1 = p1.x;
//					y1 = p1.y;
//					x2 = p2.x;
//					y2 = p2.y;
				}
			}
			var nx:Number = Math.min(x1, x2) - 2;
			nx = Math.max(0, nx);
			var ny:Number = Math.min(y1, y2) - 2;
			ny = Math.max(0, ny);
			var nw:Number = Math.abs(x1 - x2) + 4;
			var nh:Number = Math.abs(y1 - y2) + 4;
			this.width = nw;
			this.height = nh;
			this.move(nx,ny);
			this.xFrom = x1 - nx;
			this.yFrom = y1 - ny;
			this.xTo = x2 - nx;
			this.yTo = y2 - ny;
		}
		
		override public function refresh():void{
			super.refresh();
			switch(this.status){
				case StatusType.LINE_NORMAL:
					this.skin.currentState = "normal"
					break;
				case StatusType.LINE_HOVER:
					this.skin.currentState = "hover";
					break;
				case StatusType.LINE_SELECT:
					this.skin.currentState = "select";
					break;
				case StatusType.LINE_DRAW:
					this.skin.currentState = "draw";
					break;
				case StatusType.LINE_SAMPLE:
					this.skin.currentState = "normal"
					break;
				default:
					break;
			}
		}
		
		[Bindable]
		public function get xFrom():Number{
			return this._xFrom;
		}
		
		public function set xFrom(xf:Number):void{
			this._xFrom = xf;
		}
		
		[Bindable]
		public function get yFrom():Number{
			return this._yFrom
		}
		
		public function set yFrom(yf:Number):void{
			this._yFrom = yf;
		}
		
		[Bindable]
		public function get xTo():Number{
			return this._xTo;
		}
		
		public function set xTo(xt:Number):void{
			this._xTo = xt;
		}
		
		[Bindable]
		public function get yTo():Number{
			return this._yTo
		}
		
		public function set yTo(yt:Number):void{
			this._yTo = yt;
		}
		
		public function get fromPoint():Point{
			var p:Point = new Point();
			p.x = this.x + this._xFrom;
			p.y = this.y + this._yFrom;
			return p;
		}
		
		public function get toPoint():Point{
			var p:Point = new Point();
			p.x = this.x + this._xTo;
			p.y = this.y + this._yTo;
			return p;
		}
		
		[Bindable]
		public function get bidirection():Boolean{
			return this._bidirection;
		}
		
		public function set bidirection(bidi:Boolean):void{
			this._bidirection = bidi;
		}
		
		public function get startNode():WorkNode{
			return this._startNode;
		}
		
		public function set startNode(node:WorkNode):void{
			this._startNode = node;
			this.resize();
		}
		
		public function get endNode():WorkNode{
			return this._endNode;
		}
		
		public function set endNode(node:WorkNode):void{
			this._endNode = node;
			this.resize();
		}
		
		public function set mousePoint(p:Point):void{
			this._mousePoint.x = p.x;
			this._mousePoint.y = p.y;
			this.resize();
		}
		
		public function clearEndPoints():void{
			this._startNode = null;
			this._endNode = null;
		}
		
		public function setEndPoints(start:WorkNode, end:WorkNode):void{
			this._startNode = start;
			this._endNode = end;
			this.resize();
		}
		
	}
}